﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using CellarDoor.Gui.Controller;
using CellarDoor.Gui.Animation;
using CellarDoor.Gui.Theming;
using CellarDoor.Gui.Layout;

namespace CellarDoor.Gui.Elements
{
    public partial class UiElement
    {
        private UiManager manager;
        /// <summary>
        /// Gets the associated <see cref="UiManager"/>
        /// </summary>
        /// <exception cref="UiException">Thrown when the manager is null</exception>
        public UiManager Manager
        {
            get
            {
                if (manager != null)
                {
                    return manager;
                }
                throw new UiException("Manager is not set.");
            }
            private set
            {
                if (manager != value)
                {
                    if (manager != null)
                    {
                        manager.ViewportChanged -= OnManagerViewportChanged;
                    }

                    this.manager = value;

                    if (manager != null)
                    {
                        manager.ViewportChanged += OnManagerViewportChanged;
                    }

                    Invalidate();

                    if (ManagerChanged != null)
                    {
                        ManagerChanged(this, new UiEventArgs(this));
                    }

                    foreach (var item in Elements)
                    {
                        item.Manager = value;
                    }
                }
            }
        }

        /// <summary>
        /// Gets and sets the name of this element
        /// </summary>
        public string Name { get; set; }

        private UiElement parent;
        /// <summary>
        /// Gets the parent of this element
        /// </summary>
        public UiElement Parent
        {
            get { return parent; }
            internal set
            {
                if (parent != value)
                {
                    parent = value;
                    if (parent != null && manager != parent.manager && parent.manager != null)
                    {
                        Manager = parent.manager;
                    }
                    InvalidateLayout();
                }
            }
        }

        private UiElementCollection elements;
        /// <summary>
        /// Gets a collection of child elements
        /// </summary>
        public UiElementCollection Elements
        {
            get { return elements; }
        }

        private UiControllerCollection controllers = new UiControllerCollection();
        /// <summary>
        /// Gets a collection of all enabled controllers
        /// </summary>
        public UiControllerCollection Controllers
        {
            get { return controllers; }
        }

        /// <summary>
        /// Gets the navigate node of this element in the navigation graph
        /// </summary>
        public UiNavigateNode NavigateItem { get; private set; }

        /// <summary>
        /// Gets layout of this element
        /// </summary>
        public UiLayout Layout { get; set; }

        /// <summary>
        /// Gets and sets a scissor rectangle. Content outside of this rectangle is cut of.
        /// </summary>
        public Rectangle Scissor { get; set; }

        /// <summary>
        /// Enables or disables the scissor rectangle
        /// </summary>
        public bool ScissorEnable { get; set; }

        /// <summary>
        /// Gets and sets a user defined object
        /// </summary>
        public object Tag { get; set; }

        /// <summary>
        /// Gets and sets a value indicating whether this element fires and propagates mouse events.
        /// </summary>
        public bool Clickable { get; set; }

        /// <summary>
        /// Gets and sets a value indicating whether the update logic of this element is enabled or not.
        /// </summary>
        public bool Enabled { get; set; }

        /// <summary>
        /// Gets and sets a value indicating whether the element is displayed or not.
        /// </summary>
        public bool Visible { get; set; }

        /// <summary>
        /// Gets and sets a value indicating whether the elements center is to be used as drag reference point.
        /// If false, the top left corner is the drag reference
        /// </summary>
        public bool DragFromCenter { get; set; }

        /// <summary>
        /// Gets and sets a value indicating that the element may not be dragged out of the parents bounds.
        /// </summary>
        public bool DragLimitEnable { get; set; }

        /// <summary>
        /// Gets and sets a value indicating whether the component is dragable along the X axis
        /// </summary>
        public bool DragableAlongX { get; set; }

        /// <summary>
        ///  Gets and sets a value indicating whether the component is dragable along the Y axis
        /// </summary>
        public bool DragableAlongY { get; set; }

        /// <summary>
        /// Gets and sets a value indicating whether this element is dragable
        /// </summary>
        public bool Dragable
        {
            get { return DragableAlongX || DragableAlongY; }
            set { DragableAlongX = DragableAlongY = value; }
        }

        private bool lastFrameFocused = true;
        /// <summary>
        /// Gets a value indicating whether this element currently has focus or not
        /// </summary>
        public bool Focused
        {
            get { return this.Equals(Manager.ElementInFocus); }
        }

        #region Text

        /// <summary>
        /// Gets and sets the elements font name
        /// </summary>
        public string FontName
        {
            get { return Style.FontName; }
            set { Style.FontName = value; }
        }

        private string text;
        /// <summary>
        /// Gets and sets the displayed text
        /// </summary>
        public string Text
        {
            get { return text; }
            set
            {
                if (text != value)
                {
                    text = value;
                    Layout.Invalid = true;
                }
            }
        }

        /// <summary>
        /// Gets and sets the text color
        /// </summary>
        public Vector3 TextColor { get; set; }

        /// <summary>
        /// Gets and sets the text offset inside the element
        /// </summary>
        public Vector2 TextLocation
        {
            get { return Layout.TextLocation; }
            set { Layout.TextLocation = value; }
        }

        /// <summary>
        /// Gets and sets the text alignment
        /// </summary>
        public UiAlignStyle TextAlign
        {
            get { return Layout.TextAlign; }
            set { Layout.TextAlign = value; }
        }
        #endregion

        #region Layout
        /// <summary>
        /// Gets and sets the elements offset to its parent element in native resolution
        /// </summary>
        public Vector2 Location
        {
            get { return Layout.Location; }
            set { Layout.Location = value; }
        }

        /// <summary>
        /// Gets and sets the elements width and height in native resolution
        /// </summary>
        public Vector2 Size
        {
            get { return Layout.Size; }
            set { Layout.Size = value; }
        }

        /// <summary>
        /// Gets and sets the elements width in native resolution
        /// </summary>
        public float Width
        {
            get { return Layout.Size.X; }
            set { Layout.Size = new Vector2(value, Layout.Size.Y); }
        }

        /// <summary>
        /// Gets and sets the elements height in native resolution
        /// </summary>
        public float Height
        {
            get { return Layout.Size.Y; }
            set { Layout.Size = new Vector2(Layout.Size.X, value); }
        }

        /// <summary>
        /// Gets and sets the elements top edge distance from the parents top edge in native resolution
        /// </summary>
        public float Top
        {
            get { return Layout.Location.Y; }
            set { Layout.Location = new Vector2(Layout.Location.X, value); }
        }

        /// <summary>
        /// Gets and sets the elements left edge distance from the parents left edge in native resolution
        /// </summary>
        public float Left
        {
            get { return Layout.Location.X; }
            set { Layout.Location = new Vector2(value, Layout.Location.Y); }
        }

        /// <summary>
        /// Gets and sets the elements align style.
        /// </summary>
        public UiAlignStyle Align
        {
            get { return Layout.Align; }
            set { Layout.Align = value; }
        }

        /// <summary>
        /// Gets and sets the dock style of this element. This has an effect
        /// when the parent element has an active <see cref="UiDockController"/>
        /// </summary>
        public UiDockStyles Dock
        {
            get { return Layout.Dock; }
            set { Layout.Dock = value; }
        }

        /// <summary>
        /// Gets and sets the element padding in native resolution
        /// </summary>
        public UiPadding Padding
        {
            get { return Layout.Padding; }
            set { Layout.Padding = value; }
        }

        /// <summary>
        /// Gets and sets the element margin in native resolution
        /// </summary>
        public UiPadding Margin
        {
            get { return Layout.Margin; }
            set { Layout.Margin = value; }
        }
        #endregion

        #region Style
        /// <summary>
        /// Gets and sets the element name to style this element
        /// </summary>
        public string ElementName 
        {
            get { return Style.ElementName; }
            set { Style.ElementName = value; }
        }

        /// <summary>
        /// Gets and sets the opacity value
        /// </summary>
        public float Opacity { get; set; }

        /// <summary>
        /// Gets and sets the element color
        /// </summary>
        public Vector3 Color { get; set; }

        /// <summary>
        /// Gets the visual style of this element
        /// </summary>
        public UiVisualStyle Style { get; protected set; }
        #endregion
    }
}
